
#include <QCloseEvent>
#include <QClipboard>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "os_dependence.h"
#include "aboutdialog.h"
#include "clientinfodialog.h"
#include "aboutobjectdialog.h"
#include "utils.h"



Settings MainWindow::_settings;

MainWindow::MainWindow(DBusConnector *dbus_c, QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    killer_block(false),
    _no_close(true),
    exit_on_emty_client_list(false),
    dont_ask_again(false),
    ip_line_custom_text(3),
    as_dialog(0)
{
    /* set dbus connector pointer */
    _dbus_c = dbus_c;

    /* setup ui */
    ui->setupUi(this);
    //ui->actionShare_folder->setDisabled(true);

    readSettings();

    /* enable context menu */
    ui->shared_listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->clients_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->log_listWidget->setContextMenuPolicy(Qt::CustomContextMenu);

    /* build bar */
    buildBar();
    setupIcons();

    setupShortCuts();

    /* place icon in tray */
    setupTrayActions();
    systray->show();

    /* calculate interface for sharing files */
    //QString address;
    foreach(QNetworkInterface interface, QNetworkInterface::allInterfaces())
    {
        if (interface.flags().testFlag(QNetworkInterface::IsRunning)) {
            foreach (QNetworkAddressEntry entry, interface.addressEntries())
            {
                QString ip = entry.ip().toString();
                if ( interface.hardwareAddress() != "00:00:00:00:00:00" &&
                     ip != "127.0.0.1" &&
                     ip.contains("."))
                {
                    ui->ip_comboBox->addItem( QString("%1 (%2)").arg(interface.name() ).arg( entry.ip().toString() ), QString(entry.ip().toString() ) );
                    //address = QString(entry.ip().toString());
                    break;
                }
            }
        }
    }

    // ОыАы?
    //if(address.isEmpty())
    //    ui->ip_comboBox->addItem( QString( "localhost (127.0.0.1)" ), QString( "127.0.0.1" ) );

    /* init server */
    server = new Server();

    connect(server, SIGNAL(log(const QString &, uint)), this, SLOT(appendLog(const QString &, uint)));
    connect(server, SIGNAL(clientConnected( ClientThread * )), this, SLOT(addClient(ClientThread * )));
    connect(server, SIGNAL(clientDisconected(const QString & )), this, SLOT(removeClient(const QString & )));
    connect(ui->actionCopy_host_address_to_clipboard, SIGNAL(triggered()), this, SLOT(copyAddressToClipboard()));
    connect(ui->actionHide_to_tray, SIGNAL(triggered()), this, SLOT(hideToTray() ));
    connect(ui->actionCreate_virtual_folder, SIGNAL(triggered()), this, SLOT(letsCreateFolder()));
    connect(ui->actionShare_file, SIGNAL(triggered()), this, SLOT(letsShareFile()));
    connect(ui->actionShare_folder, SIGNAL(triggered()), this, SLOT(letsShareFolder()));

    connect(ui->menuConnection_log, SIGNAL(aboutToShow()), this, SLOT(menuConnectionLogShow()));

    ustack.push("/");
    ui->way_lineEdit->setText(ustack.last());

    vfs_c = server->vfs.root();

    /* load session file */
    fs_session.setSessionFile(QDir::homePath() + "/.session.dsvfs");

    /* try restore */
    if( !fs_session.restoreSession(&server->vfs) )
        flushVfsList(server->vfs.root());

    dbusSetup();

    barInformer = new StatusBarInformer(ui->statusBar, server->clientsDataBase());
    connect(barInformer, SIGNAL(uploading()), this, SLOT(animateTrayUpload()));
    connect(barInformer, SIGNAL(quiescentState()), this, SLOT(trayQuiescentState()));

    connect(server, SIGNAL(UpdateBar()), this, SLOT(updateBar()));

    exit_on_emty_client_list = false;
}


MainWindow::~MainWindow()
{
    uploadAnimation.clear();

    if(barInformer)
        delete barInformer;

    if(_dbus_c)
        delete _dbus_c;
    delete server;
    delete ui;
    delete systray;
    delete trayIconMenu;
    delete trayAnimation;
}


void MainWindow::readSettings()
{
    ui->actionLock_add->setChecked( settings().log.lock_add );
}


void MainWindow::updateBar()
{
    barInformer->update();
}



void MainWindow::setDefaultTrayIcon()
{
    systray->setIcon(defaultTrayIcon);
}


void MainWindow::setupShortCuts()
{
    QAction *act = new QAction(tr("Delete"), ui->shared_listWidget);
    ui->shared_listWidget->addAction(act);
    act->setShortcut(Qt::Key_Delete);
    connect(act, SIGNAL(triggered()), this, SLOT(contextDeletePressed()));

}


void MainWindow::setupTrayActions()
{
    systray = new QSystemTrayIcon(this);
    defaultTrayIcon = QIcon(":/icons/images/ds.png");
    setDefaultTrayIcon();

    connect(systray, SIGNAL(activated(QSystemTrayIcon::ActivationReason )), this, SLOT(systrayClicked(QSystemTrayIcon::ActivationReason )));

    QAction *exit = new QAction(QIcon(":/icons/images/exit.png"), tr("&Quit"), this);
    connect(exit, SIGNAL(triggered()), this, SLOT(on_exit_action_triggered()));

    QAction *copyAddress = new QAction(QIcon(":/icons/images/clipboard.png"), tr("&Copy address to clipboard"), this);
    connect(copyAddress, SIGNAL(triggered()), this, SLOT(copyAddressToClipboard()));

    trayIconMenu = new QMenu(this);

    trayIconMenu->addAction(copyAddress);
    trayIconMenu->addAction(exit);

    systray->setContextMenu(trayIconMenu);

    uploadAnimation.push_back(QIcon(":/icons/images/tray_upload/upload_tray_01.png"));
    uploadAnimation.push_back(QIcon(":/icons/images/tray_upload/upload_tray_02.png"));
    uploadAnimation.push_back(QIcon(":/icons/images/tray_upload/upload_tray_03.png"));
    uploadAnimation.push_back(QIcon(":/icons/images/tray_upload/upload_tray_04.png"));
    uploadAnimation.push_back(QIcon(":/icons/images/tray_upload/upload_tray_05.png"));
    uploadAnimation.push_back(QIcon(":/icons/images/tray_upload/upload_tray_06.png"));
    trayAnimation = new AnimateTrayIcon(systray, &uploadAnimation);
}



void MainWindow::dbusSetup()
{
    if(!_dbus_c) return;
    connect(_dbus_c, SIGNAL(shareObjects(QStringList)), this, SLOT(shareNewObjects(QStringList)));
}


void MainWindow::CloseWindow()
{
    killer_block = false;
    _no_close = false;

    server->c_database.waitForEmpty();

    if(as_dialog) {
        as_dialog->close();
        delete as_dialog;
        as_dialog = 0;
    }

    close();
}



void MainWindow::hideToTray()
{
    hide();
}


void MainWindow::ServerAbortAndExit(MainWindow *window)
{
    window->server->abort();
    window->CloseWindow();
}



void MainWindow::disconnectAllAndExit()
{
    dont_ask_again = true;
    /* сохраняем сессионный файл */
    fs_session.saveSession(&server->vfs);

    /* прекращаем работу сервера, отключаем всех клиентов */
    exit_on_emty_client_list = true;
    server->abort();

    if(as_dialog) {
        as_dialog->close();
        if(as_dialog->ui->mem_checkBox->isChecked())
            settings().exit_on_connected.type = 1;

        delete as_dialog;
    }
    as_dialog = 0;
}


void MainWindow::forceDisconnectAllAndExit()
{
    dont_ask_again = true;
    /* сохраняем сессионный файл */
    fs_session.saveSession(&server->vfs);

    /* прекращаем работу сервера, отключаем всех клиентов */
    exit_on_emty_client_list = true;
    server->force_abort();

    if(as_dialog) {
        as_dialog->close();
        if(as_dialog->ui->mem_checkBox->isChecked())
            settings().exit_on_connected.type = 2;

        delete as_dialog;
    }
    as_dialog = 0;
}


void MainWindow::close_event_hide()
{
    if(as_dialog) {
        as_dialog->close();
        if(as_dialog->ui->mem_checkBox->isChecked())
            settings().window_close.type = 1;

        delete as_dialog;
    }
    as_dialog = 0;

    hideToTray();
}


void MainWindow::close_event_close()
{
    if(as_dialog) {
        as_dialog->close();
        if(as_dialog->ui->mem_checkBox->isChecked())
            settings().window_close.type = 0;

        delete as_dialog;
    }
    as_dialog = 0;

    CloseWindow();
}


void MainWindow::closeEvent(QCloseEvent *event)
{
    if(_no_close){

        if(settings().window_close.type == 0) goto _exit;

        if(settings().window_close.type == 1) {
            hideToTray();
            event->ignore();
            return;
        }

        as_dialog = new ActionSelectDialog(this);
        as_dialog->setWindowTitle("Choise");

        as_dialog->ui->action_label->setText("Hide - hide to tray\nClose - exit from programm");
        as_dialog->ui->pushButton->setText("Hide");
        connect(as_dialog->ui->pushButton, SIGNAL(clicked()), this, SLOT(close_event_hide()));

        as_dialog->ui->pushButton1->setText("Close");
        connect(as_dialog->ui->pushButton1, SIGNAL(clicked()), this, SLOT(close_event_close()));

        as_dialog->ui->pushButton2->setText("Cancel");
        connect(as_dialog->ui->pushButton2, SIGNAL(clicked()), as_dialog, SLOT(close()));

        as_dialog->ui->mem_checkBox->setChecked(false);
        as_dialog->setModal(true);
        as_dialog->show();

        event->ignore();
        return;
    }

    if(!dont_ask_again)
    {
        _exit:
        emit server->connections_lock();

        if(server->c_database.size() < 1) {
            fs_session.saveSession(&server->vfs);
            return;
        }

        if(settings().exit_on_connected.type == 1)
            emit disconnectAllAndExit();
        else if(settings().exit_on_connected.type == 2)
            emit forceDisconnectAllAndExit();


        if(settings().exit_on_connected.type != 0) goto finish;

        as_dialog = new ActionSelectDialog(this);
        as_dialog->setWindowTitle("Choise");

        as_dialog->ui->action_label->setText("Server still have connections, what to do?");
        as_dialog->ui->pushButton->setText("Disconnect && exit");
        connect(as_dialog->ui->pushButton, SIGNAL(clicked()), this, SLOT(disconnectAllAndExit()));

        as_dialog->ui->pushButton1->setText("Force exit");
        connect(as_dialog->ui->pushButton1, SIGNAL(clicked()), this, SLOT(forceDisconnectAllAndExit()));

        as_dialog->ui->pushButton2->setText("Cancel");
        connect(as_dialog->ui->pushButton2, SIGNAL(clicked()), as_dialog, SLOT(close()));

        as_dialog->ui->mem_checkBox->setChecked(false);
        as_dialog->setModal(true);
        as_dialog->show();

        /* блокируем закрытие окна */
        finish:
        killer_block = true;
    }

    if(killer_block)
        event->ignore();
}


void MainWindow::appendLog(const QString & text, uint color)
{
    if(settings().log.lock_add) return;

    logmutex.lock();
    QStringList list = text.split("\n");


    foreach(QString t, list)
    {
        if(t.isEmpty())
            continue;

        if(isspace(t.at(t.length()-1).toAscii()))
            ui->log_listWidget->addItem(t.remove(t.length()-1, 1));
        else
            ui->log_listWidget->addItem(t);

        if(ui->log_listWidget->count() > 0)
            ui->log_listWidget->item(ui->log_listWidget->count()-1)->setTextColor(QColor(color));
    }

    int cnt = ui->log_listWidget->count();

    if(cnt > settings().log.max_log_size) {
        while(ui->log_listWidget->count() > settings().log.max_log_size)
            delete ui->log_listWidget->item(0);
    }

    ui->log_listWidget->scrollToBottom();
    logmutex.unlock();
}



void MainWindow::setupIcons()
{
    ui->actionCopy_host_address_to_clipboard->setIcon((icons.edit_copy = QIcon::fromTheme("edit-copy")));
    ui->actionSettings->setIcon(QIcon::fromTheme("configure"));
    ui->actionCreate_virtual_folder->setIcon(QIcon::fromTheme("folder-new"));
    ui->actionShare_folder->setIcon(QIcon::fromTheme("folder-remote"));
    ui->actionShare_file->setIcon(QIcon::fromTheme("unknown"));
    ui->actionSave->setIcon(QIcon::fromTheme("document-save"));
    ui->actionRestore->setIcon(QIcon::fromTheme("edit-undo"));
    ui->actionRestore_and_append->setIcon(QIcon::fromTheme("edit-undo"));
    ui->actionKik_all->setIcon(QIcon::fromTheme("format-disconnect-node"));
    ui->actionForce_disconnect_all->setIcon(QIcon::fromTheme("format-disconnect-node"));
    ui->actionClear->setIcon(QIcon::fromTheme("edit-clear"));
    ui->actionLock_add->setIcon(QIcon::fromTheme("emblem-locked"));
    ui->actionAbout->setIcon(QIcon::fromTheme("help-about"));
}


void MainWindow::buildBar()
{
    QAction *action1 = ui->mainToolBar->addAction(QIcon(QString::fromUtf8(":/icons/images/server.png")),
                                         trUtf8("Start"));
    QObject::connect(action1, SIGNAL(triggered()), this, SLOT(start_server()));

    action1 = ui->mainToolBar->addAction(QIcon(QString::fromUtf8(":/icons/images/server_stop.png")),
                                         trUtf8("Stop"));
    QObject::connect(action1, SIGNAL(triggered()), this, SLOT(stop_server()));

    action1 = ui->mainToolBar->addAction(QIcon(QString::fromUtf8(":/icons/images/vfolder.png")),
                                         trUtf8("Create folder"));

    QObject::connect(action1, SIGNAL(triggered()), this, SLOT(letsCreateFolder()));

    action1 = ui->mainToolBar->addAction(QIcon(QString::fromUtf8(":/icons/images/vfile.png")),
                                         trUtf8("Share file"));
    QObject::connect(action1, SIGNAL(triggered()), this, SLOT(letsShareFile()));


    action1 = ui->mainToolBar->addAction(QIcon(QString::fromUtf8(":/icons/images/folder.png")),
                                         trUtf8("Share folder"));
    QObject::connect(action1, SIGNAL(triggered()), this, SLOT(letsShareFolder()));


    action1 = ui->mainToolBar->addAction(QIcon(QString::fromUtf8(":/icons/images/exit.png")),
                                         trUtf8("Exit"));
    QObject::connect(action1, SIGNAL(triggered()), this, SLOT(CloseWindow()));
}



void MainWindow::on_ip_comboBox_editTextChanged(const QString &arg1) {
    Q_UNUSED(arg1)
    qWarning() << __FUNCTION__;
    
    // At run combo-box called this, we check for it
    if(ip_line_custom_text != 3)
	ip_line_custom_text = true;
    else
	ip_line_custom_text = false;
}


void MainWindow::on_ip_comboBox_activated(int index) {
    Q_UNUSED(index)
    qWarning() << __FUNCTION__;
	ip_line_custom_text = false;
}


void MainWindow::start_server()
{
    QString ip;

    if(ip_line_custom_text)
        ip = ui->ip_comboBox->currentText();
    else
        ip = ui->ip_comboBox->itemData( ui->ip_comboBox->currentIndex() ).toString();

    qWarning() << "ip: " << ip;

    server->init_host(QHostAddress(ip), ui->port_spinBox->value());
}


void MainWindow::stop_server()
{
    server->stop();
}


void MainWindow::addClient(ClientThread * t)
{
    qWarning() << __FUNCTION__;
    clientmutex.lock();

    connect(t, SIGNAL(txRxSizeRefreshed(int, int)), barInformer, SLOT(addTxRxValue(int,int)));

    int sz = server->c_database.size();
    ui->clients_treeWidget->clear();

    for(int i=0; i<sz; ++i)
    {
        QTreeWidgetItem *qtreewidgetitem = new QTreeWidgetItem(ui->clients_treeWidget);
        qtreewidgetitem->setText(0, server->c_database.at(i, true)->_ip);
    }
    clientmutex.unlock();
}


void MainWindow::removeClient(const QString & ip)
{
    qWarning() << __FUNCTION__ << ip;

    clientmutex.lock();
    int sz = server->c_database.size();
    ui->clients_treeWidget->clear();

    for(int i=0; i<sz; ++i)
    {
        QTreeWidgetItem *qtreewidgetitem = new QTreeWidgetItem(ui->clients_treeWidget);
        qtreewidgetitem->setText(0, server->c_database.at(i, true)->_ip);
    }
    clientmutex.unlock();

    if(exit_on_emty_client_list && sz < 1)
        CloseWindow();
}



void MainWindow::shareFile(const QString & _dir, const QString & file)
{
    QString dir = file.left(file.lastIndexOf(Slash)+1);

    int tt = file.length() - file.lastIndexOf(Slash);
    QString name = file.right( tt-1 );

    server->vfs.addFile(dir, _dir, name, 1);
}


void MainWindow::shareFolder(const QString & folder)
{
    QString n = folder;
    if(!n.endsWith("/")) n += "/";
    server->vfs.addFolder(n, true);
}


void MainWindow::letsShareFile()
{
    QStringList list = QFileDialog::getOpenFileNames(this, trUtf8("Select files"));

    foreach(QString file, list)
    {
        shareFile(ustack.last(), file);
    }

    ui->shared_listWidget->clear();
    flushVfsList(vfs_c);
}



// TEST
void MainWindow::letsShareFolder()
{
    QString directory = QFileDialog::getExistingDirectory(this, QString("Select dir"));
    if(directory.isEmpty()) return;

    quint64 cnt = 0;
    int cut = directory.length();

    if(directory.endsWith('/'))
        cut -= 1;

    /* делаем резиновый стек */
    QStack <QDir *> dstack;
    dstack.push(new QDir(directory));

    while(!dstack.isEmpty())
    {
        QDir *d = dstack.last();
        dstack.pop();

        directory = d->absolutePath();
        QFileInfoList list = d->entryInfoList();
        delete d;

        if(list.isEmpty()) continue;

        foreach(QFileInfo fi, list)
        {
            QString ap = fi.absoluteFilePath();
            qWarning() << ap << (fi.isDir()? " - Dir" : " - File") << fi.absoluteFilePath();
            if(fi.isDir())
            {
                if(directory.length() >= fi.absoluteFilePath().length())
                    continue;

                qWarning() << fi.absoluteDir();
                server->vfs.addFolder(currentFolder() + QString(ap).remove(0, cut) + "/");
                dstack.push(new QDir(fi.absoluteFilePath()));
            } else
            {
                QString t = QString(ap).remove(0, cut);
                QString vway = Utils::foldeFromWay(t), name = Utils::nameFromWay(t);

                qWarning() << vway << name;

                qWarning() << "Add file: " << t;
                server->vfs.addFile(Utils::foldeFromWay(ap), currentFolder() + vway, name);
                cnt++;
            }
        }
    }

    qWarning() << "added " << cnt;
    refreshCurrentFolder();
}


QString MainWindow::currentFolder()
{
    QString r = ustack.last();
    if(r == "/") return QString();
    int l = r.length();
    return r.remove(l-1, 1);
}


void MainWindow::vfolderCreate(const QString & name)
{
    qWarning() << __FUNCTION__ << ustack.last() + name + "/";
    if(server->vfs.addFolder(ustack.last() + name + "/"))
        QMessageBox::critical(qobject_cast<QWidget *>(sender()), "Error", "Cant create the folder.");
    else
        refreshCurrentFolder();
}


void MainWindow::letsCreateFolder()
{
    qWarning() << "dialog create";

    VfolderCreateDialog *dialog = new VfolderCreateDialog(this);

    dialog->setModal(true);

    dialog->show();

    connect(dialog, SIGNAL(createFolder(const QString &)), this, SLOT( vfolderCreate(const QString &) ));
}



void MainWindow::refreshCurrentFolder(VirtualFsObject *vfso)
{
    if(!vfso)
        vfso = server->vfs.folder(ustack.last());
    ui->shared_listWidget->clear();
    flushVfsList(vfso);
}



bool MainWindow::jumpToFolder(VirtualFsObject *obj, const QString & f )
{
    VirtualFsObject *vfso = server->vfs.folder(obj, f);
    if(!vfso) return false;

    /* current VirtualFsObject object */
    vfs_c = vfso;

    if(vfso->name().isEmpty())
        ustack.push( vfso->virtualWay() );
    else
        ustack.push( vfso->virtualWay() + "/" + vfso->name() + "/");

    qWarning() << "cur " << ustack.last() << vfso->virtualWay();

    ui->way_lineEdit->setText(ustack.last());
    refreshCurrentFolder(vfso);
    return true;
}


void MainWindow::setListItemStyle(QListWidgetItem *item, bool hidden, bool dir)
{
    Q_UNUSED(dir)
    static QColor theme_color = item->textColor();

    QFont font = item->font();
    font.setItalic(hidden);
    item->setFont(font);

    if(hidden)
        item->setTextColor(QColor(88, 88, 88));
    else
        item->setTextColor(theme_color);
}


void MainWindow::flushVfsList(VirtualFsObject *vfs)
{
    if(!vfs) return;

    filesmutex.lock();
    for(int i = 0; i<vfs->size(); ++i)
    {
        bool isdir = vfs->at(i)->isDir();
        bool visible = vfs->at(i)->isHidden();
        if(!isdir) continue;

        QString name = "/" + vfs->at(i)->name() + "/";
        QListWidgetItem *item = new QListWidgetItem(QIcon(":/icons/images/folder.png"), name);

        setListItemStyle(item, visible, true);

        ui->shared_listWidget->addItem( item );
    }
    ui->shared_listWidget->sortItems();

    for(int i = 0; i<vfs->size(); ++i)
    {
        bool isdir = vfs->at(i)->isDir();
        bool visible = vfs->at(i)->isHidden();
        if(isdir) continue;

        QString name = vfs->at(i)->name();
        QListWidgetItem *item = new QListWidgetItem(QIcon(":/icons/images/file.png"), name);

        setListItemStyle(item, visible, false);

        ui->shared_listWidget->addItem( item );
    }
    filesmutex.unlock();
}


void MainWindow::on_shared_listWidget_itemDoubleClicked(QListWidgetItem *item)
{
    qWarning() << "cliked to " << item->text();

    jumpToFolder(vfs_c, item->text());
}


/* back */
void MainWindow::on_back_pushButton_clicked()
{
    if(ustack.size() > 1)
        ustack.pop();

    qWarning() << "cur " << ustack.last();

    ui->way_lineEdit->setText(ustack.last());

    VirtualFsObject *vfso = server->vfs.folder(ustack.last());
    vfs_c = vfso;
    refreshCurrentFolder(vfso);
}


void MainWindow::on_shared_listWidget_customContextMenuRequested(const QPoint &pos)
{
    QList <QListWidgetItem*> items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty())
    {
        qWarning() << "Empty selected" << pos;
    }else
    {
        static bool initialized = false;
        if(!initialized) {
            initialized = true;
            icons.doc_open_folder = QIcon::fromTheme("document-open-folder");
            icons.edit_rename = QIcon::fromTheme("edit-rename");
            icons.edit_del = QIcon::fromTheme("edit-delete");
            icons.user_visible = QIcon::fromTheme("layer-visible-on");
            icons.user_invisible = QIcon::fromTheme("layer-visible-off");
            icons.info = QIcon::fromTheme("dialog-information");
        }

        QMenu contextMenu(tr("Context menu"), ui->shared_listWidget);

        QAction *act = new QAction(icons.doc_open_folder, tr("Open"), ui->shared_listWidget);
        contextMenu.addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextOpenPressed()));

        act = new QAction(icons.edit_copy, tr("Copy address"), ui->shared_listWidget);
        contextMenu.addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextCopyAddressPressed()));


        contextMenu.addSeparator();
        act = new QAction(icons.edit_rename, tr("Rename"), ui->shared_listWidget);
        contextMenu.addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextRenamePressed()));

        act = new QAction(icons.edit_del, tr("Delete"), ui->shared_listWidget);
        contextMenu.addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextDeletePressed()));

        QIcon *visibility = &icons.user_visible;
        if(items.size() < 2) {
            VirtualFsObject *obj = virtualFsObjectByNameInCurDir(items.first()->text());
            if(obj && obj->isHidden()) {
                visibility = &icons.user_invisible;
            }
        }

        QMenu *visible_menu = contextMenu.addMenu(*visibility, tr("Set hidden mode"));
        act = new QAction(icons.user_visible, tr("Visible"), act);
        visible_menu->addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextSetVisible()));

        act = new QAction(icons.user_invisible, tr("Invisible"), act);
        visible_menu->addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextSetInvisible()));


        contextMenu.addSeparator();
        act = new QAction(icons.info, tr("Information"), ui->shared_listWidget);
        contextMenu.addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextInfoPressed()));

        contextMenu.exec(ui->shared_listWidget->mapToGlobal(pos));
    }
}



void MainWindow::contextOpenPressed()
{
    QList <QListWidgetItem*> items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty()) return;

    qWarning() << "oO" << items[0]->text();

    on_shared_listWidget_itemDoubleClicked(items[0]);
}



VirtualFsObject * MainWindow::virtualFsObjectByNameInCurDir(QString patch)
{
    if(patch.endsWith("/"))
        patch.remove(0, 1);

    QString name = ustack.last() + patch;

    //qWarning() << "Get: " << name;

    VirtualFsObject *obj;

    if(name.endsWith("/"))
        obj = server->vfs.folder(name);
    else
        obj = server->vfs.file(name);

    return obj;
}


void MainWindow::contextCopyAddressPressed()
{
    QList <QListWidgetItem*> items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty()) return;

    QString c;
    QString root = QString("http://%1:%2%3").arg(server->ip()).arg(server->port()).arg(ustack.last());
    QClipboard *clip = QApplication::clipboard();

    if(items.size() == 1)
    {
        QString name = items[0]->text();
        if( name.startsWith('/') )
            name.remove(0, 1);
        c += root + name;
        clip->setText(c);
        return;
    }

    foreach(QListWidgetItem *i, items)
    {
        QString name = i->text();
        if( name.startsWith('/') )
            name.remove(0, 1);

        c += root + name + "\n";
    }

    clip->setText(c);
}


/* slot */
void MainWindow::fileHasBeenRenamed(QString from, QString to)
{
    if(server->vfs.rename(from, to))
    {
        QMessageBox::critical(this, "Error", "Can not rename");
        return;
    }
    refreshCurrentFolder();
}


void MainWindow::contextRenamePressed()
{
    QList <QListWidgetItem*> items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty()) return;

    if(items.size() > 1) {
        QMessageBox::information(this, "Info", "You cannot rename multiple files!");
        return;
    }

    QString item = items.at(0)->text();
    bool isFile = true;

    if(item[0] == '/') {
        item.remove(0, 1);
        isFile = false;
    }

    item = ustack.last() + item;
    RenameDialog *d = new RenameDialog(item, isFile, this);
    connect(d, SIGNAL(renamed(QString, QString)), this, SLOT(fileHasBeenRenamed(QString, QString)));
    d->setModal(true);
    d->show();
}



void MainWindow::contextDeletePressed()
{
    QList <QListWidgetItem*> items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty()) return;

    for(int i=0; i<items.size(); i++)
    {
        QString item_name = items[i]->text();
        QString name = ustack.last();

        if(item_name.startsWith("/"))
            name = name + item_name.remove(0, 1);
        else
            name = name + item_name;

        qWarning() << "Removed " << name;

        if(server->vfs.isFolder( name ))
            server->vfs.rmdir( name );
        else
            server->vfs.rm( name );
    }

    refreshCurrentFolder();
}



void MainWindow::contextInfoPressed()
{
    QList <QListWidgetItem*> items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty()) return;

    VirtualFsObject *obj = virtualFsObjectByNameInCurDir(items.first()->text());
    if(!obj) return;

    qDebug() << "name: " << obj->name();
    qDebug() << "way: " << obj->virtualWay();
    qDebug() << "real name: " << obj->realName();
    qDebug() << "real way: " << obj->realWay();

    AboutObjectDialog *ad = new AboutObjectDialog(ustack.last(), obj, this);
    ad->setModal(true);
    ad->show();
}


void MainWindow::contextSetInvisible()
{
    const QList <QListWidgetItem*> & items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty()) return;

    for(int i=0; i<items.size(); i++)
    {
        VirtualFsObject *obj = virtualFsObjectByNameInCurDir(items.at(i)->text());
        if(!obj) {
            qWarning() << "virtualFsObjectByPatch getting invalid object";
        }

        obj->setVisible(false);

        setListItemStyle(items.at(i), true, obj->isDir());
    }
}


void MainWindow::contextSetVisible()
{
    const QList <QListWidgetItem*> & items = ui->shared_listWidget->selectedItems();
    if(items.isEmpty()) return;

    for(int i=0; i<items.size(); i++)
    {
        VirtualFsObject *obj = virtualFsObjectByNameInCurDir(items.at(i)->text());
        if(!obj) {
            qWarning() << "virtualFsObjectByPatch getting invalid object";
        }

        obj->setVisible(true);

        setListItemStyle(items.at(i), false, obj->isDir());
    }
}


void MainWindow::on_exit_action_triggered()
{
    _no_close = false;
    close();
}



void MainWindow::systrayClicked( QSystemTrayIcon::ActivationReason reason)
{
    //qWarning() << __FUNCTION__;

    switch (reason) {
        case QSystemTrayIcon::Context:
            break;

        default:
            if( isHidden() )
                show();
            else
                hideToTray();
            break;
    }
}


/* about */
void MainWindow::on_actionAbout_triggered()
{
    AboutDialog *about = new AboutDialog(this);
    about->show();
}



void MainWindow::copyAddressToClipboard()
{
    if(server->ip().isEmpty()) {
        QMessageBox::information(this, tr("Aborted"), tr("First start server"));
        return;
    }

    QClipboard *clip = QApplication::clipboard();
    clip->setText(QString("http://%1:%2").arg(server->ip()).arg(server->port()) );
}



void MainWindow::shareNewObjects(QStringList list)
{
    qWarning() << list;

    foreach(QString n, list)
    {
        if(n.endsWith(Slash))
        {
            qWarning() << "Not support at this moment. Share " << n;
        } else {
            qWarning() << "Share" << n;
            shareFile("/", n);
        }
    }

    if(ustack.last() == "/")
    {
        refreshCurrentFolder();
    }
}



/* client list context menu */
void MainWindow::on_clients_treeWidget_customContextMenuRequested(const QPoint &pos)
{
    QList <QTreeWidgetItem*> items = ui->clients_treeWidget->selectedItems();
    qWarning() << pos;

    if(!items.isEmpty())
    {
        QMenu contextMenu(tr("Context menu"), ui->clients_treeWidget);

        QAction *act = new QAction(tr("Information"), ui->clients_treeWidget);
        contextMenu.addAction(act);
        connect(act, SIGNAL(triggered()), this, SLOT(contextClientInfo()));

        QAction *kick = new QAction(tr("Kick"), ui->clients_treeWidget);
        contextMenu.addAction(kick);
        connect(kick, SIGNAL(triggered()), this, SLOT(contextClientKick()));

        contextMenu.exec(ui->clients_treeWidget->mapToGlobal(pos));
    }
}



void MainWindow::contextClientInfo()
{
    QList <QTreeWidgetItem*> items = ui->clients_treeWidget->selectedItems();
    if(items.isEmpty()) return;

    qWarning() << "ip:" << items[0]->text(0);

    int n;
    if( (n = server->c_database.findClientByIP(items[0]->text(0))) > -1)
    {
        ClientInfoDialog *cdiag = new ClientInfoDialog(server->c_database.at(n), this);
        cdiag->setModal(true);
        cdiag->show();
    } else {
        qWarning() << "Not found O_o";
    }
}



void MainWindow::contextClientKick()
{
    QList <QTreeWidgetItem*> items = ui->clients_treeWidget->selectedItems();
    if(items.isEmpty()) return;

    int n;
    if( (n = server->c_database.findClientByIP(items[0]->text(0))) > -1)
    {
        server->c_database.at(n)->abort();
    }
}




/* Session save */
void MainWindow::on_actionSave_triggered()
{
    //"*.dsvfs"
    QString f = QFileDialog::getSaveFileName(this, trUtf8("Save session"), QDir::homePath());
    if(f.isEmpty()) return;

    VirtualFsSession vsession;
    vsession.setSessionFile(f);

    int err;
    if( (err= vsession.saveSession(&server->vfs)) )
    {
        switch(err)
        {
            case -1:
                QMessageBox::critical(this, tr("Error"), tr("Can not save the virtual fs file, check your permission"));
                break;

            case -2:
                QMessageBox::critical(this, tr("Error"), tr("The virtual fs is empty or missing"));
                break;

            default:
                QMessageBox::critical(this, tr("Error"), tr("Unknow error"));
                break;
        }
    }
}



void MainWindow::on_actionRestore_triggered()
{
    QString f = QFileDialog::getOpenFileName(this, trUtf8("Select virtual fs file session"));
    if(f.isEmpty()) return;

    server->vfs.clear(server->vfs.root());

    restoreSessionFromFile(f);
    refreshCurrentFolder();
}


void MainWindow::on_actionRestore_and_append_triggered()
{
    QString f = QFileDialog::getOpenFileName(this, trUtf8("Select virtual fs file session"));
    if(f.isEmpty()) return;

    restoreSessionFromFile(f);
    refreshCurrentFolder();
}


void MainWindow::restoreSessionFromFile(const QString &f)
{
    if(f.isEmpty()) return;

    VirtualFsSession vsession;
    vsession.setSessionFile(f);

    int err;
    if( (err= vsession.restoreSession(&server->vfs)) )
    {
        switch(err)
        {
            case -1:
                QMessageBox::critical(this, tr("Error"), tr("Can not open the virtual fs file, check your permission"));
                break;

            case -2:
                QMessageBox::critical(this, tr("Error"), tr("Session file has wrong type"));
                break;

            default:
                QMessageBox::critical(this, tr("Error"), tr("Unknow error"));
                break;
        }
    }
}



void MainWindow::on_way_lineEdit_returnPressed()
{
    QString p = ui->way_lineEdit->text();
    if( p == ustack.last() ) return;

    if(p == "/")
    {
        jumpToFolder(server->vfs.root(), "/");
        return;
    }

    if(p.endsWith("/"))
    {
        jumpToFolder(server->vfs.root(), p);
    }
}



void MainWindow::animateTrayUpload()
{
    trayAnimation->start();
}


void MainWindow::trayQuiescentState()
{
    trayAnimation->stop();
    setDefaultTrayIcon();
}



/* kik all clienst */
void MainWindow::on_actionKik_all_triggered()
{
    QStringList list = server->c_database.clientsIpList();
    server->c_database.killClientsByIpList(list);
}


/* log clear */
void MainWindow::on_actionClear_triggered()
{
    ui->log_listWidget->clear();
}


/* lock log */
void MainWindow::on_actionLock_add_triggered()
{
    settings().log.lock_add = ui->actionLock_add->isChecked();
}

/* Connection log menu show */
void MainWindow::menuConnectionLogShow()
{
    ui->actionLock_add->setChecked(settings().log.lock_add);
}


void MainWindow::async_kill(ClientsDataBase *base, QStringList *list)
{
    qWarning() << "async kill started " << list->size();
    base->killClientsByIpList(*list, false, true);
    qWarning() << "async kill finished";

    delete list;
}


void MainWindow::on_actionForce_disconnect_all_triggered()
{
    qWarning() << __FUNCTION__;
    QStringList *list = new QStringList(server->c_database.clientsIpList());

    //scheduler.schedule((void*)async_kill, &server->c_database, list);
    server->c_database.killClientsByIpList(*list, false, true);
    delete list;
}


void MainWindow::on_actionSettings_triggered()
{
    SettingsDialog *dialog = new SettingsDialog(&_settings, this);
    dialog->setModal(true);
    dialog->show();
}



void MainWindow::on_log_listWidget_customContextMenuRequested(const QPoint &pos)
{
    QList <QListWidgetItem*> items = ui->log_listWidget->selectedItems();
    qWarning() << pos;

    QMenu contextMenu(tr("Context menu"), ui->log_listWidget);

    bool empty = items.isEmpty();

    QAction *act = new QAction(tr(empty?"Clear" : "Copy"), ui->log_listWidget);
    contextMenu.addAction(act);

    if(!empty)
        connect(act, SIGNAL(triggered()), this, SLOT(contextLogCopy()));
    else
        connect(act, SIGNAL(triggered()), ui->log_listWidget, SLOT(clear()));

    contextMenu.exec(ui->log_listWidget->mapToGlobal(pos));
}



void MainWindow::contextLogCopy()
{
    QList <QListWidgetItem*> items = ui->log_listWidget->selectedItems();
    QString data;

    foreach(QListWidgetItem *item, items)
    {
        data += item->text() + "\n";
    }

    QApplication::clipboard()->setText(data);
}
